﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Diagnostics;
using Xceed.Silverlight.Compatibility;

namespace Xceed.Silverlight.Data
{
  [DebuggerDisplay( "FilterBy = {DebuggerDisplayString}" )]
  public sealed class FilterExpression : FilterExpressionBase
  {
    #region Constructors

    public FilterExpression( string memberName, FilterOperator filterOperator, object value )
      : this( memberName, filterOperator, value, null, null )
    {
    }

    public FilterExpression( string memberName, FilterOperator filterOperator, string value, bool? isCaseSensitive )
      : this( memberName, filterOperator, value, isCaseSensitive, null )
    {
    }

    public FilterExpression( string memberName, FilterOperator filterOperator, DateTime value, bool? isTimeSensitive )
      : this( memberName, filterOperator, value, null, isTimeSensitive )
    {
    }

    public FilterExpression()
    {
      //Note: This constructor is there to allow XAML declaration of FilterExpressions
    }

    internal FilterExpression( string memberName, FilterOperator filterOperator, object value, bool? isCaseSensitive, bool? isTimeSensitive )
    {
      this.Initialize( memberName, filterOperator, value, isCaseSensitive, isTimeSensitive );
    }

    private FilterExpression( FilterExpression copy )
    {
      this.Initialize( copy.MemberName, copy.FilterOperator, copy.Value, copy.IsCaseSensitive, copy.IsTimeSensitive );
    }

    #endregion

    #region MemberName Property

    public string MemberName
    {
      get
      {
        return m_memberName;
      }
      set
      {
        if( this.IsFrozen )
          throw new InvalidOperationException( "A FilterExpression cannot be modified once it has been frozen." );

        if( value != m_memberName )
        {
          m_memberName = value;
        }
      }
    }

    private string m_memberName;

    #endregion

    #region FilterOperator Property

    public FilterOperator FilterOperator
    {
      get
      {
        return m_operator;
      }
      set
      {
        if( this.IsFrozen )
          throw new InvalidOperationException( "A FilterExpression cannot be modified once it has been frozen." );

        if( value != m_operator )
        {
          m_operator = value;
        }
      }
    }

    private FilterOperator m_operator;

    #endregion

    #region Value Property

    public object Value
    {
      get
      {
        return m_value;
      }
      set
      {
        if( this.IsFrozen )
          throw new InvalidOperationException( "A FilterExpression cannot be modified once it has been frozen." );

        if( value != m_value )
        {
          m_value = value;
        }
      }
    }

    private object m_value; //null

    #endregion

    #region IsCaseSensitive Property

    public bool? IsCaseSensitive
    {
      get
      {
        return m_isCaseSensitive;
      }
      set
      {
        if( this.IsFrozen )
          throw new InvalidOperationException( "A FilterExpression cannot be modified once it has been frozen." );

        if( value != m_isCaseSensitive )
        {
          m_isCaseSensitive = value;
        }
      }
    }

    private bool? m_isCaseSensitive;

    #endregion

    #region IsTimeSensitive Property

    public bool? IsTimeSensitive
    {
      get
      {
        return m_isTimeSensitive;
      }
      set
      {
        if( this.IsFrozen )
          throw new InvalidOperationException( "A FilterExpression cannot be modified once it has been frozen." );

        if( value != m_isTimeSensitive )
        {
          m_isTimeSensitive = value;
        }
      }
    }

    private bool? m_isTimeSensitive;

    #endregion

    public override int GetHashCode()
    {
#if WINDOWS_PHONE
      this.Freeze();
#endif

      if( m_memberName == null )
        return 0;

      return m_memberName.GetHashCode();
    }

    public override bool Equals( object obj )
    {
#if WINDOWS_PHONE
      this.Freeze();
#endif

      if( object.ReferenceEquals( this, obj ) )
        return true;

      FilterExpression expression = obj as FilterExpression;
      if( expression == null )
        return false;

      if( expression.GetHashCode() != this.GetHashCode() )
        return false;

      return ( object.Equals( expression.FilterOperator, this.FilterOperator ) )
          && ( object.Equals( expression.IsCaseSensitive, this.IsCaseSensitive ) )
          && ( object.Equals( expression.IsTimeSensitive, this.IsTimeSensitive ) )
          && ( object.Equals( expression.MemberName, this.MemberName ) )
          && ( object.Equals( expression.Value, this.Value ) );
    }

    internal override FilterExpressionBase Clone()
    {
#if WINDOWS_PHONE
      this.Freeze();
#endif

      return new FilterExpression( this );
    }

    [DebuggerStepThrough]
    internal override void Accept( FilterExpressionVisitor visitor )
    {
#if WINDOWS_PHONE
      this.Freeze();
#endif

      if( visitor != null )
      {
        visitor.Visit( this );
      }
    }

    internal override void FreezeOverride()
    {
      // For Phone SDK Compatibility
      if( StringHelper.IsNullOrWhiteSpace( m_memberName ) )
        throw new InvalidOperationException( "A MemberName must be specified in order for the FilterExpression to be valid." );

      if( !Enum.IsDefined( typeof( FilterOperator ), m_operator ) )
        throw new InvalidOperationException( "A FilterOperator must be specified in order for the FilterExpression to be valid." );

      base.FreezeOverride();
    }

    private void Initialize(
      string memberName,
      FilterOperator filterOperator,
      object value,
      bool? isCaseSensitive,
      bool? isTimeSensitive )
    {
      m_memberName = memberName;
      m_operator = filterOperator;
      m_value = value;
      m_isCaseSensitive = isCaseSensitive;
      m_isTimeSensitive = isTimeSensitive;
    }
  }
}
